package com.jiang.annotation.aop.global_log;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.StringJoiner;

@Component
@Aspect
@Slf4j
public class ReqRspLogAspect {

    @Resource
    private HttpServletRequest request;

    @Around("@annotation(org.springframework.web.bind.annotation.GetMapping) " +
            "|| @annotation(org.springframework.web.bind.annotation.PostMapping) " +
            "|| @annotation(org.springframework.web.bind.annotation.PutMapping) " +
            "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)")
    private Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        Signature signature = joinPoint.getSignature();
        StopWatch stopWatch = new StopWatch();
        log.info("++++ 接口请求开始执行：[{}] {}; 入参：{} ++++", method, requestURI, requestParams());
        stopWatch.start();
        try {
            Object result = joinPoint.proceed();
            stopWatch.stop();
            // 执行成功才打印响应时间
            log.info("++++ 接口响应返回值：{}; cost: {}ms ++++", JSONObject.toJSONString(result), stopWatch.getTotalTimeMillis());
            return result;
        } catch (Exception e) {
            log.info("++++ 接口请求执行异常。方法名：{} cost:{}ms errMsg={} ++++", signature.getName(), stopWatch.getTotalTimeMillis(), e.getMessage());
            throw e;
        }
    }

    private String requestParams() {
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringJoiner params = new StringJoiner(";");
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            params.add(entry.getKey() + ":" + Arrays.toString(entry.getValue()));
        }
        return params.toString();
    }
}
